tweak(gui): Decouple GUI transition and world animation timing from render update#2056
tweak(gui): Decouple GUI transition and world animation timing from render update#2056bobtista wants to merge 8 commits into
Conversation
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Include/GameClient/GameWindowTransitions.h | Changes m_currentFrame from Int to Real with an updated doc-comment; correct and self-contained. |
| Core/GameEngine/Source/GameClient/GUI/GameWindowTransitions.cpp | Correctly uses getBaseOverUpdateFpsRatio() to advance the fractional frame accumulator; step-loop with early-break for finished transitions is sound. |
| Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp | Uses getActualLogicTimeScaleOverFpsRatio() which returns 1.0 in the default uncapped mode, making the Z-rise fix ineffective unless the logic-time-scale feature is explicitly enabled. |
| GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp | Same getActualLogicTimeScaleOverFpsRatio() issue as in the Generals variant — Z-rise remains frame-rate dependent under the default game configuration. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Render Frame] --> B[TransitionGroup::update]
A --> C[InGameUI::updateAndDrawWorldAnimations]
B --> D["timeScale = getBaseOverUpdateFpsRatio()\n= BaseFps / renderFps"]
D --> E["m_currentFrame += dirMult * timeScale"]
E --> F{newFrame != prevFrame?}
F -- Yes --> G[Step through each integer frame\nand call tWin->update]
F -- No --> H[Return early, no state change]
G --> I{All transitions finished?}
I -- Yes --> J[Break early]
I -- No --> G
C --> K["zRiseTimeScale = getActualLogicTimeScaleOverFpsRatio()\n= min(1.0, logicFps / renderFps)"]
K --> L{Logic time scale enabled?}
L -- Yes --> M["Returns logicFps/renderFps ✓\ne.g. 30/60 = 0.5"]
L -- No/Default --> N["logicFps = UncappedFpsValue (1,000,000)\nReturns 1.0 regardless of renderFps ✗"]
M --> O["z += zRisePerSecond / 30 * 0.5\n= frame-rate independent ✓"]
N --> P["z += zRisePerSecond / 30 * 1.0\n= still frame-rate dependent ✗"]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Render Frame] --> B[TransitionGroup::update]
A --> C[InGameUI::updateAndDrawWorldAnimations]
B --> D["timeScale = getBaseOverUpdateFpsRatio()\n= BaseFps / renderFps"]
D --> E["m_currentFrame += dirMult * timeScale"]
E --> F{newFrame != prevFrame?}
F -- Yes --> G[Step through each integer frame\nand call tWin->update]
F -- No --> H[Return early, no state change]
G --> I{All transitions finished?}
I -- Yes --> J[Break early]
I -- No --> G
C --> K["zRiseTimeScale = getActualLogicTimeScaleOverFpsRatio()\n= min(1.0, logicFps / renderFps)"]
K --> L{Logic time scale enabled?}
L -- Yes --> M["Returns logicFps/renderFps ✓\ne.g. 30/60 = 0.5"]
L -- No/Default --> N["logicFps = UncappedFpsValue (1,000,000)\nReturns 1.0 regardless of renderFps ✗"]
M --> O["z += zRisePerSecond / 30 * 0.5\n= frame-rate independent ✓"]
N --> P["z += zRisePerSecond / 30 * 1.0\n= still frame-rate dependent ✗"]
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp:5508
**Wrong FramePacer method — fix is a no-op in the default game mode**
`getActualLogicTimeScaleOverFpsRatio()` returns `min(1.0f, logicFps / renderFps)`. When logic time scale is *disabled* (the default), `getActualLogicTimeScaleFps()` returns `RenderFpsPreset::UncappedFpsValue` (= 1 000 000), so this ratio collapses to `min(1.0, 1000000/renderFps) = 1.0` at any practical frame rate. `zRiseTimeScale` is thus always 1.0 in single-player without the logic-time-scale feature enabled, and the Z-rise remains frame-rate dependent.
The transition code correctly uses `getBaseOverUpdateFpsRatio()` (= `BaseFps / renderFps` = `30 / renderFps`), which scales down proportionally at any render fps without requiring the logic time scale feature. The world-animation fix should use the same method. The same issue is present in `GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp`.
Reviews (6): Last reviewed commit: "fix(gui): Check transition completion du..." | Re-trigger Greptile
Additional Comments (1)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! Prompt To Fix With AIThis is a comment left during a code review.
Path: Generals/Code/GameEngine/Source/GameClient/GUI/GameWindowTransitions.cpp
Line: 62:62
Comment:
[P2] This file still uses `NULL` (`TheTransitionHandler = NULL;`). New code in this PR also adds `FramePacer` usage; consider switching to `nullptr` for null pointer literals to match the repo’s C++ style.
```suggestion
GameWindowTransitionsHandler *TheTransitionHandler = nullptr;
```
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise. |
|
I frequently find myself increasing the render frame rate at the menu because I find the window transitions too slow at 30 fps, and would probably like it better if they played close to ~1.75x the original speed. Is there anything this PR can do in that regard? |
|
I agree with Caball. It would be nice to have a setting to adjust GUI speed (x1.0... x1.25... x1.5x... x1.75... x2.00... and so on). |
|
Feature for scaling animation speed is unrelated to decoupling step and better be follow up change. |
|
Looks good. |
276ed5c to
e6cd525
Compare
|
There are still a couple of to-dos in the PR description. |
Is this something you can reproduce? I don't think I've seen anything like this during my testing. |
|
I ran into this several times when testing. My SSD was slow, but still it was unusual behavior. I can retest if this is not reproducible for others. |
Please do. |
Can you take a look at this? I cannot reproduce it, and this PR probably shouldn't be blocked from merging if you can't reproduce it either |
|
I replicated Xezon's bug by running this on a networked drive. The logic seems to fail on long IO stalls. |
|
Added a single sleep to replicate this, the menu won't even launch on this. But it does on main. GameEngine.cpp 30 will randomly bug out the menu after a few switches. |
|
|
@bobtista Can you take a look at the stuck menu issue? |
| it++; | ||
| } | ||
|
|
||
| if( isFinished() ) |
There was a problem hiding this comment.
This goes through the list a second time. This can probably be optimized by returning finished result in update function above and then use that to determine finished status.
There was a problem hiding this comment.
Or just check isFinished for each transition group after each update.
|
I've addressed the remaining review comments and tested the menu-stall repro locally:
|




Summary
Changes
TransitionGroup::m_currentFramechanged fromInttoRealto support fractional frame accumulationTransitionGroup::update()scales frame advancement byTheFramePacer->getActualLogicTimeScaleOverFpsRatio()InGameUIworld animation Z-rise calculation now scales by the same time factorTest plan